﻿using Abp.Migration;
using FluentNHibernate.Mapping;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
namespace Abp.NHibernate
{
    /// <summary>
    /// NHibernate 实体映射实现
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class NhEntityMapper<T> : ClassMap<T>, IEntityMapper<T>
    {
        public string TableName { get; set; }
        public string SchemaName { get; set; }
        public string IdName { get; set; }
        public Dictionary<string, Tuple<string, string, string, string, string, string>> ForeignKeyConfigurationCollection { get; set; }
        public List<Tuple<string, string, string, string>> AnnotationConfigurationCollection { get; set; }
        public NhEntityMapper()
        {
            this.TableName = typeof(T).Name;
            ForeignKeyConfigurationCollection = new Dictionary<string, Tuple<string, string, string, string, string, string>>();
            AnnotationConfigurationCollection = new List<Tuple<string, string, string, string>>();
            AnnotationConfigurationCollection.Add(new Tuple<string, string, string, string>(
                this.SchemaName,
                this.TableName,
                null,
                EntityDescriptionUtils.GetTableDescription<T>()));
        }
        public new IdentityPart Id(Expression<Func<T, object>> memberExpression)
        {
            this.IdName = GetColumnName(memberExpression);
            AnnotationConfigurationCollection.Add(new Tuple<string, string, string, string>(
               this.SchemaName,
               this.TableName,
               IdName,
               EntityDescriptionUtils.GetColumnDescription<T>(IdName)));
            return base.Id(memberExpression);
        }
        public new void Schema(string schema)
        {
            this.SchemaName = schema;
            base.Schema(schema);
        }
        public new void Table(string tableName)
        {
            this.TableName = tableName;
            base.Table(tableName);
        }
        public new PropertyPart Map(Expression<Func<T, object>> memberExpression)
        {
            string columnName = GetColumnName(memberExpression);
            AnnotationConfigurationCollection.Add(new Tuple<string, string, string, string>(
               this.SchemaName,
               this.TableName,
               columnName,
               EntityDescriptionUtils.GetColumnDescription<T>(columnName)));
            return base.Map(memberExpression);
        }
        public new PropertyPart Map(Expression<Func<T, object>> memberExpression, string columnName)
        {
            AnnotationConfigurationCollection.Add(new Tuple<string, string, string, string>(
               this.SchemaName,
               this.TableName,
               columnName,
               EntityDescriptionUtils.GetColumnDescription<T>(columnName)));
            return base.Map(memberExpression, columnName);
        }
        private string GetColumnName(Expression<Func<T, object>> memberExpression)
        {
            return memberExpression.Body.ToString().Split('.')[1].TrimEnd(')');
        }
        public void ForeignKey<TEntityMapper>(Expression<Func<T, object>> memberExpression, string foreignKeyName = "") where TEntityMapper : IEntityMapper
        {
            var entityMapper = Activator.CreateInstance<TEntityMapper>();
            if (string.IsNullOrWhiteSpace(this.IdName))
                throw new Exception(string.Format("{0}没有配置主键。", this.TableName));
            if (string.IsNullOrWhiteSpace(entityMapper.IdName))
                throw new Exception(string.Format("{0}没有配置主键。", entityMapper.TableName));
            string columnName = GetColumnName(memberExpression);
            if (string.IsNullOrWhiteSpace(foreignKeyName) || ForeignKeyConfigurationCollection.ContainsKey(foreignKeyName))
                foreignKeyName = string.Format("FK_{0}_{1}_{2}_Ref_{3}_{4}_{5}", this.SchemaName, this.TableName, columnName, entityMapper.SchemaName, entityMapper.TableName, entityMapper.IdName);
            ForeignKeyConfigurationCollection[foreignKeyName] = new Tuple<string, string, string, string, string, string>(
                this.SchemaName,
                this.TableName,
                columnName,
                entityMapper.SchemaName,
                entityMapper.TableName,
                entityMapper.IdName);
        }
    }
}
